#include <sys/epoll.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
#include <vector>
#include <memory>
#include "Connection.hpp"

class Epoll
{
public:
   Epoll()
       : _epFd(-1)
   {
      _epFd = epoll_create(1);
      if (_epFd < 0)
      {
         std::cerr << "Epoll::Epoll()::epoll_create err..." << std::endl;
      }
   }

   bool Add(const Connection& conn, int events)
   {
      struct epoll_event eve;
      bzero(&eve, sizeof(eve));
      eve.events = events;
      eve.data.fd = conn.Fd();
      if (epoll_ctl(_epFd, EPOLL_CTL_ADD, conn.Fd(), &eve) < 0)
      {
         std::cerr << "Epoll::Add::epoll_ctl err..." << std::endl;
         return false;
      }
      return true;
   }

   bool Modify(const Connection& conn, int events)
   {
      struct epoll_event eve;
      bzero(&eve, sizeof(eve));
      eve.events = events;
      eve.data.fd = conn.Fd();
      if (epoll_ctl(_epFd, EPOLL_CTL_MOD, conn.Fd(), &eve) < 0)
      {
         std::cerr << "Epoll::Modify::epoll_ctl err..." << std::endl;
         return false;
      }
      return true;
   }

   bool Delete(const Connection& conn)
   {
      if (epoll_ctl(_epFd, EPOLL_CTL_DEL, conn.Fd(), nullptr) < 0)
      {
         std::cerr << "Epoll::Delete::epoll_ctl err..." << std::endl;
         return false;
      }
      return true;
   }

   bool Wait(std::vector<Connection> *ready)
   {
      struct epoll_event rEvents[100] = {0};
      int nFds = epoll_wait(_epFd, rEvents, sizeof(rEvents) / sizeof(rEvents[0]), 1000);
      if (nFds < 0)
      {
         std::cerr << "Epoll::Wait::epoll_wait err..." << std::endl;
         return false;
      }
      else if (nFds == 0)
      {
         std::cout << "timeout..." << std::endl;
         return false;
      }
      else
      {
         for (int i = 0; i < nFds; ++i) {
            ready->push_back(Connection(rEvents[i].data.fd, nullptr, nullptr, nullptr, this));
         }
      }
      return true;
   }

   ~Epoll()
   {
      close(_epFd);
      _epFd = -1;
   }

private:
   int _epFd;
};
